home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume25 / pty4 / part03 < prev    next >
Encoding:
Text File  |  1992-02-19  |  64.0 KB  |  2,446 lines

  1. Newsgroups: comp.sources.unix
  2. From: brnstnd@nyu.edu (Dan Bernstein)
  3. Subject: v25i129 REPOST: Generalized interface to pseudo-tty devices, Part03/09
  4. Sender: unix-sources-moderator@pa.dec.com
  5. Approved: vixie@pa.dec.com
  6.  
  7. [ the first version of part03 had a raw \r floating around in one of
  8.   the strings, and nntp doesn't do well with this.  i changed the raw
  9.   \r to a "\r" that the c compiler will convert back to a raw one. --vix ]
  10.  
  11. Submitted-By: brnstnd@nyu.edu (Dan Bernstein)
  12. Posting-Number: Volume 25, Issue 129
  13. Archive-Name: pty4/part03
  14.  
  15. #! /bin/sh
  16. # This is a shell archive.  Remove anything before this line, then unpack
  17. # it by saving it into a file and typing "sh file".  To overwrite existing
  18. # files, type "sh file -c".  You can also feed this as standard input via
  19. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  20. # will see the following message at the end:
  21. #        "End of archive 3 (of 9)."
  22. # Contents:  CHANGES CHECKCONF.c IMPACT WTF getopt.c pty-basic.1
  23. #   ptycomm.c ptyget.c ptyslave.c ptytexts.c radixsort.3 ralloc.c
  24. #   sesslist.c sessmenu.c sessname.c sigdfl.c who.c write.c
  25. # Wrapped by vixie@cognition.pa.dec.com on Wed Feb 19 13:35:03 1992
  26. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  27. if test -f 'CHANGES' -a "${1}" != "-c" ; then 
  28.   echo shar: Will not clobber existing file \"'CHANGES'\"
  29. else
  30. echo shar: Extracting \"'CHANGES'\" \(3883 characters\)
  31. sed "s/^X//" >'CHANGES' <<'END_OF_FILE'
  32. X2/9/92: pty 4.0.
  33. X2/9/92: Fixed up documentation, hopefully for the last time.
  34. X1/29/92: Changed INSTALL.c to report chown root for INSTALL root. Tnx IS.
  35. X1/27/92: Added ABRT->IOT ifndef in sigdfl.c.
  36. X1/27/92: Changed sigdfl.c to zero the sigvecs rather than setting sv_flags.
  37. X1/16/92: pty 4.0, second gamma.
  38. X1/13/92: Does it work on an Iris? Nobody knows. 
  39. X1/13/92: Added IRIS_UGH_PTYS to ptyget.c. Tnx IRIS, I think.
  40. X1/13/92: Changed fatal to warning for tctpgrp failure in ptyslave.c. Tnx IRIS.
  41. X1/13/92: ifndef'ed SYSV for ut_host in ptylogs.c. Tnx IRIS.
  42. X1/13/92: Added config/sysv.h to distribution. Tnx IRIS.
  43. X1/13/92: Added PTYLIBS, noted its use in README. Tnx IRIS.
  44. X1/13/92: Replaced CCOPTMZ with OPTMZ.
  45. X1/13/92: Noted in CALLS that TTY_TERMIO seems to work. Tnx IRIS.
  46. X1/13/92: Adapted tty_initmodes for TTY_TERMIO. Ugh, ugh. Tnx IRIS.
  47. X1/13/92: Adapted tty_mungemodes for TTY_TERMIO. Ugh. Tnx IRIS.
  48. X1/13/92: Adapted tty_modifymodes for TTY_TERMIO (poorly). Tnx IRIS.
  49. X1/13/92: Adapted tty_getmodes and tty_setmodes for TTY_TERMIO. Tnx IRIS.
  50. X1/13/92: In ptytty.c used ifdefs for FIONREAD and TIOCEXCL. Tnx IRIS.
  51. X1/13/92: Adapted ptytty.h for TTY_TERMIO. Tnx IRIS.
  52. X1/13/92: Added TTY_TERMIO option to config/ttyopts.h. Tnx IRIS.
  53. X1/13/92: Gave in and made tty_copymodes do a struct copy.
  54. X1/13/92: Fixed typo in SECURITY. Tnx KS.
  55. X1/13/92: Fixed typo in pty-basic.1. Tnx KS.
  56. X1/12/92: Replaced <sgtty.h> with <sys/ioctl.h> in ptytty.h. Tnx IRIS.
  57. X1/12/92: Added chmod 700 for all shell scripts in Makefile.
  58. X1/12/92: Removed <sys/timeb.h> from wall.c and write.c. Tnx IRIS.
  59. X1/12/92: In separate effort got it working on an IRIS. See above.
  60. X12/22/91: pty 4.0, first gamma! (Still have to integrate BSD 4.4 version.)
  61. X12/22/91: Changed various things in the documentation.
  62. X12/22/91: Fixed exit code reporting for, e.g., DIE_NOPTYS.
  63. X12/22/91: Changed POSIX to POSIX_SILLINESS. See config/posix.h.
  64. X12/20/91: Added CCOPTMZ in Makefile for radixsort.
  65. X12/19/91: Added BLURB.
  66. X12/19/91: Added TESTS.
  67. X12/19/91: Cleaned up README.
  68. X12/19/91: Added WTF, noted SunOS 4.0.3 forcefg bug in README.
  69. X12/18/91: Fixed bug in sessmenu's sesslist parsing.
  70. X12/17/91: Fixed up documentation a bit; referred to checkptys in README.
  71. X12/16/91: Added CPP define to Makefile.
  72. X12/15/91: Added -xi.
  73. X12/15/91: Started machine list in Makefile.
  74. X12/15/91: Added EWOULDBLOCK in ptysecure.c for Domain/OS.
  75. X12/14/91: Added target-list target.
  76. X12/14/91: Added lint target.
  77. X12/13/91: Changed master so that it continues child on any reconnect. Tnx SS.
  78. X11/24/91: Changed master to run only as effective uid.
  79. X11/18/91: Added TERM, USR1, USR2 ignoring to master. Tnx SS.
  80. X11/9/91: Added \fP in syntax sections in pty-opts.1, pty.1. Tnx SS.
  81. X11/9/91: Added <sys/types.h> before <utmp.h> in {users,who}.c. Domain/OS idiocy.
  82. X11/9/91: Fixed dependencies for CHECKCONF and INSTALL.
  83. X11/3/91: Added proper .h dependencies in Makefile (finally).
  84. X10/27/91: Added exit(0) at end of sesslist.c. Tnx SS.
  85. X10/27/91: Fixed ptysecure.c---it didn't undo chmod for some setups. Tnx SS.
  86. X10/27/91: Added make clean. Tnx SS.
  87. X10/27/91: Added checkptys.8.
  88. X10/27/91: Changed checkptys to be installed non-setuid.
  89. X10/26/91: Added pty.1, pty-basic.1, pty-opts.1, sess.1, condom.1.
  90. X10/26/91: Tossed old man pages.
  91. X10/26/91: Added DIE_EXIST for ptysigler.c.
  92. X10/26/91: Added DIE_ELSE for ptysigler.c.
  93. X10/26/91: Fixed ptymain to die(SETMODES) in an impossible situation.
  94. X10/26/91: Changed a few die() values in ptymain.c.
  95. X10/25/91: Need to add *.h to Makefile...
  96. X10/25/91: Removed last traces of old getopt schizophrenia.
  97. X10/25/91: Changed *rotate to preserve modes of log files.
  98. X10/25/91: Added sessnowinit, scnowinit.
  99. X10/25/91: Added sessrotate, sclogrotate.
  100. X10/25/91: Fixed off-by-one on remotelen.
  101. X10/25/91: Changed wtmprotate to depend on config/wtmpfile.h properly.
  102. X[log is not complete before this point]
  103. X10/6/91: Added -xsS.
  104. X9/30/91: pty 4.0, second beta.
  105. END_OF_FILE
  106. if test 3883 -ne `wc -c <'CHANGES'`; then
  107.     echo shar: \"'CHANGES'\" unpacked with wrong size!
  108. fi
  109. # end of 'CHANGES'
  110. fi
  111. if test -f 'CHECKCONF.c' -a "${1}" != "-c" ; then 
  112.   echo shar: Will not clobber existing file \"'CHECKCONF.c'\"
  113. else
  114. echo shar: Extracting \"'CHECKCONF.c'\" \(2724 characters\)
  115. sed "s/^X//" >'CHECKCONF.c' <<'END_OF_FILE'
  116. X#include <stdio.h>
  117. X#include <sys/types.h>
  118. X#include <sys/time.h>
  119. X#include <sys/stat.h>
  120. X#include <sys/file.h>
  121. X#include "config/fdsettrouble.h"
  122. X#include "config/genericptr.h"
  123. X#include "config/devmty.h"
  124. X#include "config/devsty.h"
  125. X#include "config/posix.h"
  126. X#include "config/ptybin.h"
  127. X#include "config/ptydir.h"
  128. X#include "config/ptyext.h"
  129. X#include "config/ptygroup.h"
  130. X#include "config/ptylongname.h"
  131. X#include "config/ptymodes.h"
  132. X#include "config/ptyopts.h"
  133. X#include "config/ttyopts.h"
  134. X#include "config/sessconnfile.h"
  135. X#include "config/sessfile.h"
  136. X#include <utmp.h>
  137. X#include "config/utmpfile.h"
  138. X#include "config/wtmpfile.h"
  139. X#include <grp.h>
  140. X
  141. main()
  142. X{
  143. X int nothing;
  144. X struct group *grp;
  145. X printf("Check through this list carefully.\n");
  146. X printf("master tty extension: %s\n",DEVMTY);
  147. X printf("slave tty extension: %s\n",DEVSTY);
  148. X printf("pty names: %s[%s][%s]\n",DEVMTY,PTYEXT1,PTYEXT2);
  149. X printf("pty binary directory: %s\n",PTYBIN);
  150. X printf("pty session directory: %s\n",PTYDIR);
  151. X printf("utmp file: %s  wtmp file: %s\n",UTMP_FILE,WTMP_FILE);
  152. X printf("session-connection now: %s  log: %s\n",SESSCONNNOW_FILE,SESSCONNLOG_FILE);
  153. X printf("session now: %s  log: %s\n",SESSNOW_FILE,SESSLOG_FILE);
  154. X#ifdef DESPERATE_FD_SET
  155. X printf("DESPERATE_FD_SET turned on.\n");
  156. X#else
  157. X#ifdef LACKING_FD_ZERO
  158. X printf("LACKING_FD_ZERO turned on.\n");
  159. X#else
  160. X printf("System must have normal fd_set and FD_ZERO support.\n");
  161. X#endif
  162. X#endif
  163. X /* XXX: GENERICPTR? */
  164. X#ifdef POSIX_SILLINESS
  165. X printf("POSIX turned on. System must have setsid().\n");
  166. X#else
  167. X printf("POSIX turned off. System should not have setsid().\n");
  168. X#endif
  169. X printf("pty group: %d. ",PTYGROUP);
  170. X grp = getgrnam("tty");
  171. X if (!grp)
  172. X   printf("\nAack! You should add a tty group, group %d, to /etc/group.\n",PTYGROUP);
  173. X else
  174. X   if (grp->gr_gid == PTYGROUP)
  175. X     printf("Okay, this matches the tty entry in /etc/group.\n");
  176. X   else
  177. X     printf("\nAack! This doesn't match the tty group entry (%d) in /etc/group.\nYou should probably edit config/ptygroup.h.\n",grp->gr_gid);
  178. X printf("session long name length: %d\n",PTYLONGNAMELEN);
  179. X printf("pty modes: %o used %o unused\n",PTYMODE_USED,PTYMODE_UNUSED);
  180. X printf("MUSTNOT: "); nothing = 1;
  181. X#ifdef PTY_MUSTNOT_SESSION
  182. X printf("session "); nothing = 0;
  183. X#endif
  184. X#ifdef PTY_MUSTNOT_UTMPHOST
  185. X printf("utmphost "); nothing = 0;
  186. X#endif
  187. X#ifdef PTY_MUSTNOT_UTMP
  188. X printf("utmp "); nothing = 0;
  189. X#endif
  190. X#ifdef PTY_MUSTNOT_WTMP
  191. X printf("wtmp "); nothing = 0;
  192. X#endif
  193. X#ifdef PTY_MUSTNOT_CHOWN
  194. X printf("chown "); nothing = 0;
  195. X#endif
  196. X if (nothing) printf("(nothing)");
  197. X printf("\n");
  198. X#ifdef TTY_AUXCHARS
  199. X printf("System must support tty auxiliary characters.\n");
  200. X#endif
  201. X#ifdef TTY_WINDOWS
  202. X printf("System must support tty windows and SIGWINCH.\n");
  203. X#endif
  204. X exit(0);
  205. X}
  206. END_OF_FILE
  207. if test 2724 -ne `wc -c <'CHECKCONF.c'`; then
  208.     echo shar: \"'CHECKCONF.c'\" unpacked with wrong size!
  209. fi
  210. # end of 'CHECKCONF.c'
  211. fi
  212. if test -f 'IMPACT' -a "${1}" != "-c" ; then 
  213.   echo shar: Will not clobber existing file \"'IMPACT'\"
  214. else
  215. echo shar: Extracting \"'IMPACT'\" \(2458 characters\)
  216. sed "s/^X//" >'IMPACT' <<'END_OF_FILE'
  217. X  [ pty ]
  218. X> Is it self-contained, or does it
  219. X> require other mods?
  220. X
  221. There are certain decisions which anyone installing pty has to make:
  222. X
  223. X1. Should pty run setuid root, or setuid some other user, say ``pty''?
  224. If the latter, then the new user should be added to /etc/passwd, and it
  225. would help to have utmp and wtmp owned by that user. It's generally
  226. simpler to have pty running setuid root. This also lets it chown and
  227. chmod tty device files.
  228. X
  229. X2. pty's INSTALL program copies the binaries to some directory, and sets
  230. up a directory where pty can store session information. Where do those two
  231. directories go? The defaults are /usr/local/ptybin and /usr/local/etc/pty.
  232. pty also maintains four session log files analogous to utmp/wtmp, all in
  233. X/usr/local/etc by default.
  234. X
  235. X3. pty comes with some clones of existing programs: biff, lock, mesg,
  236. script, tty, users, wall, who, whoami, write. In many cases these offer
  237. features beyond the standard versions: for instance, if pty has write
  238. permission to utmp, then script (which is just a tiny shell script) will
  239. have a utmp entry, so talk/mail/write/etc. will work. Should they
  240. replace the system versions?
  241. X
  242. X4. pty comes with some programs which belong in rc.local: utmpinit does a
  243. more professional job of utmp initialization than init does; sessnowinit
  244. and scnowinit initialize pty's session log files. Should these be added to
  245. rc.local?
  246. X
  247. X5. pty comes with some programs which belong in daily, weekly, or monthly
  248. cron scripts: wtmprotate, sessrotate, and sclogrotate. On any modern
  249. system, of course, wtmp is rotated anyway, but should sessrotate and
  250. sclogrotate be added to cron scripts? One other program, checkptys,
  251. produces a report on the entire pty subsystem, and can also be run from
  252. cron.
  253. X
  254. X6. pty comes with some other utilities not directly related to session
  255. management. For instance, trecord and tplay make typescripts in a
  256. special format which includes the timing between characters. My tscript
  257. utility works just like script but makes a tapescript which you can play
  258. back later. (This is great for talk conversations and other interactive
  259. sessions.) Should these utilities be part of a user's standard path?
  260. Should pty itself be part of a user's standard path?
  261. X
  262. X7. Should some secure ttys be set aside for pty's use? It's easy to
  263. configure pty so that it only uses (e.g.) tty[u-z]*, which are always
  264. mode 600 root rather than mode 666 root. Or pty can just compete for
  265. insecure ttys like everyone else.
  266. END_OF_FILE
  267. if test 2458 -ne `wc -c <'IMPACT'`; then
  268.     echo shar: \"'IMPACT'\" unpacked with wrong size!
  269. fi
  270. # end of 'IMPACT'
  271. fi
  272. if test -f 'WTF' -a "${1}" != "-c" ; then 
  273.   echo shar: Will not clobber existing file \"'WTF'\"
  274. else
  275. echo shar: Extracting \"'WTF'\" \(2353 characters\)
  276. sed "s/^X//" >'WTF' <<'END_OF_FILE'
  277. BLURB: general blurb on what pty does for you.
  278. X
  279. README: the first thing you should read; gives basic information and
  280. credits, and tells you how to get pty running.
  281. X
  282. XFORMLETTER: the form letter you should send back to me when you get to
  283. step #12 in README.
  284. X
  285. SYSCONF: a shell script which looks for various features of your system
  286. and changes config/* accordingly.
  287. X
  288. WTF: this file, detailing what the, uh, files in this distribution are
  289. for.
  290. X
  291. CALLS: a detailed list of all the syscalls and library calls used by
  292. pty, followed by a breakdown of the calls into groups and a description
  293. of what you have to do to port each group. This is the most important
  294. file to read if you're going to port pty to a non-BSD system.
  295. X
  296. CHANGES: reverse chronological list of most of the changes to pty 4.0.
  297. X
  298. COPYRIGHT: short explanation of the copying rights I'm giving you.
  299. X
  300. XFILES: list of all the files in the pty 4.0 distribution, in some order;
  301. used by ``make shar'', for example.
  302. X
  303. OBJECTS: list of all the .o files created while compiling pty.
  304. X
  305. BINARIES: list of all the executables created by ``make''.
  306. X
  307. Makefile: instructions for make, in a reasonably portable format.
  308. X
  309. TESTS: typescript of a typical pty test run.
  310. X
  311. NEW: explanation of the important differences between pty 3.0 and pty 4.0.
  312. X
  313. NOTES: random implementation notes. This is the first place to turn to
  314. if you're not sure about something in the code.
  315. X
  316. IMPACT: rough outline of how pty affects the rest of the system.
  317. X
  318. SECURITY: dull explanation of the incredible torture pty 4.0 has to go
  319. through to ensure that a tty is ``clean''.
  320. X
  321. QUESTIONS: questions and pty-based answers, mostly stolen from the
  322. USENET newsgroup comp.unix.questions.
  323. X
  324. X*.draft*: draft papers dealing with random topics of possible interest.
  325. SESS.draft2 leads the reader through a session management tutorial.
  326. X
  327. X*.1: man pages for user programs.
  328. X
  329. X*.3: man pages for libraries.
  330. X
  331. X*.7: man pages giving general information.
  332. X
  333. X*.8: man pages for sysadmin programs.
  334. X
  335. X*.c: C source files.
  336. X
  337. X*.h: C header files.
  338. X
  339. X*.sh: sh source files. Makefile does the work of ``compiling'' these.
  340. X
  341. config/*.h: configuration files. Instead of a big config.h, or lots of
  342. options spread through Makefile or through individual files, all
  343. compile-time options are collected here. SYSCONF edits some of these.
  344. You can edit them too. Or steal them for other programs.
  345. END_OF_FILE
  346. if test 2353 -ne `wc -c <'WTF'`; then
  347.     echo shar: \"'WTF'\" unpacked with wrong size!
  348. fi
  349. # end of 'WTF'
  350. fi
  351. if test -f 'getopt.c' -a "${1}" != "-c" ; then 
  352.   echo shar: Will not clobber existing file \"'getopt.c'\"
  353. else
  354. echo shar: Extracting \"'getopt.c'\" \(3276 characters\)
  355. sed "s/^X//" >'getopt.c' <<'END_OF_FILE'
  356. X/* getopt.c, getopt.h: (yet another) improved getopt clone
  357. Daniel J. Bernstein, brnstnd@nyu.edu.
  358. No dependencies.
  359. Requires stdio.
  360. X10/20/91: Removed -DGETOPT_SHUT_UP. [sigh]
  361. X8/26/91: Added -DGETOPT_SHUT_UP.
  362. X8/25/91: Changed getopt to not skip blank arguments.
  363. X7/6/91: Baseline. getopt 1.0, public domain.
  364. No known patent problems.
  365. X
  366. This is a clone of the usual getopt() functions. It includes opterr so
  367. that you can turn off error handling, optpos so that you can find out
  368. exactly where the processing is up to (instead of just which argument),
  369. optproblem so that you can accurately diagnose errors yourself, and
  370. optprogname so that you can set the program name for getopt-generated
  371. errors. getopt() takes much more care to ensure that all the variables
  372. still make sense upon errors and EOF. (optproblem is a character. If
  373. argv[optind] is 0, the problem is a missing argument; otherwise it's an
  374. illegal option character.) Unless you define GETOPTORIGDEF, the header
  375. file redefines all names so that you don't have to worry about conflicts
  376. with libc. Finally, the code is public-domain, so you should feel free
  377. to use these extra features in your own programs and just attach a copy
  378. of this.
  379. X
  380. Note that optind and optpos can be read (or set) any time, but the
  381. official getopt interface only defines optind when getopt() returns EOF.
  382. We define optproblem only when getopt() returns '?', optarg all the
  383. time, and optprogram only after getopt() has been called at least once.
  384. X
  385. X*/
  386. X
  387. X#include <stdio.h> /* for EOF and stderr---talk about immodularity! */
  388. X#include "getopt.h"
  389. X
  390. int optind = 1;
  391. int optpos = 0;
  392. int opterr = 1;
  393. char *optarg = 0;
  394. int optproblem = 0;
  395. char *optprogname = 0;
  396. int opteof = EOF;
  397. X
  398. int getopt(argc,argv,opts)
  399. int argc;
  400. char **argv;
  401. char *opts;
  402. X{
  403. X int c;
  404. X char *s;
  405. X
  406. X optarg = 0;
  407. X if (!optprogname)
  408. X  {
  409. X   optprogname = *argv;
  410. X   if (!optprogname) /* oh boy */
  411. X     optprogname = ""; /*XXX*/
  412. X   for (s = optprogname;*s;++s)
  413. X     if (*s == '/')
  414. X       optprogname = s + 1;
  415. X  }
  416. X if (!argv || (optind >= argc) || !argv[optind])
  417. X   return opteof;
  418. X while (optpos && !argv[optind][optpos])
  419. X  {
  420. X   /* we simply skip blank arguments... not any more */
  421. X   ++optind;
  422. X   optpos = 0;
  423. X   if ((optind >= argc) || !argv[optind])
  424. X     return opteof;
  425. X  }
  426. X if (!optpos)
  427. X  {
  428. X   if (argv[optind][0] != '-')
  429. X     return opteof;
  430. X   ++optpos;
  431. X   c = argv[optind][1];
  432. X   if ((c == '-') || (c == 0))
  433. X    {
  434. X     /* XXX: this behavior of "-" is stupid */
  435. X     if (c)
  436. X       ++optind;
  437. X     optpos = 0;
  438. X     return opteof;
  439. X    }
  440. X   /* otherwise c is reassigned below */
  441. X  }
  442. X c = argv[optind][optpos];
  443. X ++optpos;
  444. X s = opts;
  445. X while (*s)
  446. X  {
  447. X   if (c == *s)
  448. X    {
  449. X     if (s[1] == ':')
  450. X      {
  451. X       optarg = argv[optind] + optpos;
  452. X       ++optind;
  453. X       optpos = 0;
  454. X       if (!*optarg)
  455. X        {
  456. X         optarg = argv[optind];
  457. X         if ((optind >= argc) || !optarg) /* argument past end */
  458. X          {
  459. X           optproblem = c;
  460. X           if (opterr)
  461. X             fprintf(stderr,"%s: option requires an argument -- %c\n"
  462. X               ,optprogname,c);
  463. X           return '?';
  464. X          }
  465. X     ++optind;
  466. X        }
  467. X      }
  468. X     return c;
  469. X    }
  470. X   ++s;
  471. X   if (*s == ':')
  472. X     ++s;
  473. X  }
  474. X optproblem = c;
  475. X if (opterr)
  476. X   fprintf(stderr,"%s: illegal option -- %c\n",optprogname,c);
  477. X return '?';
  478. X}
  479. END_OF_FILE
  480. if test 3276 -ne `wc -c <'getopt.c'`; then
  481.     echo shar: \"'getopt.c'\" unpacked with wrong size!
  482. fi
  483. # end of 'getopt.c'
  484. fi
  485. if test -f 'pty-basic.1' -a "${1}" != "-c" ; then 
  486.   echo shar: Will not clobber existing file \"'pty-basic.1'\"
  487. else
  488. echo shar: Extracting \"'pty-basic.1'\" \(3127 characters\)
  489. sed "s/^X//" >'pty-basic.1' <<'END_OF_FILE'
  490. X.TH pty-basic 1
  491. X.SH NAME
  492. pty-basic \- run a program under a pseudo-terminal session
  493. X.SH SYNTAX
  494. pty
  495. X.I program
  496. X[
  497. X.I arg ...
  498. X]
  499. X.SH DESCRIPTION
  500. This man page describes the effects of
  501. X.B pty
  502. without any options.
  503. XFor a general overview of
  504. X.B pty,
  505. see the
  506. X.B pty(1)
  507. man page.
  508. XFor a description of
  509. the options,
  510. see the
  511. X.B pty-opts(1)
  512. man page.
  513. X
  514. XExecuting
  515. X.B pty \fIprogram
  516. has approximately the same effect as executing
  517. X.I program
  518. X(with zero or more arguments).
  519. X.I program
  520. is run under a pseudo-terminal. This means several things:
  521. X
  522. X1. Its standard input, output, and error descriptors are redirected to a
  523. pseudo-terminal device driver, with effects documented in
  524. X.B pty(4)
  525. and
  526. X.B tty(4).
  527. This means that
  528. X.I program
  529. may use
  530. X.B ioctl(),
  531. for example, to affect the
  532. pseudo-terminal.
  533. So programs such as
  534. X.B vi,
  535. which normally cannot be run
  536. inside a pipe, will see a terminal instead.
  537. X(Of course,
  538. X.B pty
  539. may be put
  540. into a pipe.)
  541. X
  542. X2.
  543. X.B isatty()
  544. and stdio's buffering will consider those descriptors to be
  545. pointing to a terminal, with effects documented in
  546. X.B isatty(3)
  547. and
  548. X.B setbuf(3).
  549. This means that if 
  550. X.I program
  551. uses stdio, its output will be
  552. line-buffered.
  553. X
  554. X3. Input to
  555. X.B pty \fIprogram
  556. is passed through to the pseudo-terminal
  557. input. Output and error to the pseudo-terminal are passed through to the
  558. output of
  559. X.B pty \fIprogram.
  560. X
  561. X4.
  562. X.I program
  563. has controlling terminal set to the pseudo-terminal, with
  564. effects documented in
  565. X.B tty(4).
  566. X
  567. X5.
  568. X.B pty \fIprogram
  569. must have an original controlling tty.
  570. X.B pty
  571. considers the controlling tty to be the first of
  572. the following which responds to a TIOCGPGRP ioctl:
  573. descriptor 3, /dev/tty, descriptor 0, descriptor 1,
  574. descriptor 2.
  575. X.B pty
  576. sets that terminal to character-at-a-time, no-echo mode,
  577. to do as little processing as possible.
  578. It sets the pseudo-terminal to the original mode.
  579. When
  580. X.I program
  581. finishes,
  582. X.B pty
  583. sets the original terminal back to its original mode.
  584. Any mode changes on the pseudo-terminal will be lost.
  585. The original terminal is also reset whenever
  586. X.I program
  587. is stopped
  588. X(and then set back to character-at-a-time mode when
  589. X.I program
  590. is restarted).
  591. X
  592. X6.
  593. Various signals to
  594. X.B pty \fIprogram
  595. are converted into HUPs for
  596. X.I program.
  597. Single-process signals may fail upon
  598. X.B pty \fIprogram.
  599. Process group signals as described in
  600. X.B tty(4)
  601. will affect it normally.
  602. X
  603. X7.
  604. All normal exits (including signal exits) for
  605. X.I program
  606. are converted
  607. into exit code 0.
  608. Other exit codes indicate various new,
  609. pty-related problems, which are also announced on the standard error of
  610. X.B pty \fIprogram.
  611. X
  612. X8.
  613. All file descriptors except 0, 1, and 2 are closed.
  614. X3 is reopened as the new /dev/tty,
  615. i.e.,
  616. the pseudo-terminal.
  617. All controlling terminal ioctls
  618. mentioned in
  619. X.B tty(4)
  620. may be applied to file descriptor 3 instead.
  621. X
  622. Note that
  623. X.B pty
  624. transmits job control transparently:
  625. if
  626. X.I program
  627. stops with (say)
  628. a TTIN, then
  629. X.B pty \fIprogram
  630. will also stop with a TTIN.
  631. When
  632. X.B pty \fIprogram
  633. is continued,
  634. X.I program
  635. will receive a CONT.
  636. X.SH VERSION
  637. pty version 4.0, 2/9/92.
  638. X.SH AUTHOR
  639. Copyright 1992, Daniel J. Bernstein.
  640. X.SH "SEE ALSO"
  641. pty(1),
  642. pty-opts(1),
  643. sess(1),
  644. condom(1),
  645. pty(4),
  646. tty(4)
  647. END_OF_FILE
  648. if test 3127 -ne `wc -c <'pty-basic.1'`; then
  649.     echo shar: \"'pty-basic.1'\" unpacked with wrong size!
  650. fi
  651. # end of 'pty-basic.1'
  652. fi
  653. if test -f 'ptycomm.c' -a "${1}" != "-c" ; then 
  654.   echo shar: Will not clobber existing file \"'ptycomm.c'\"
  655. else
  656. echo shar: Extracting \"'ptycomm.c'\" \(3465 characters\)
  657. sed "s/^X//" >'ptycomm.c' <<'END_OF_FILE'
  658. X#include <sys/types.h>
  659. X#include <sys/time.h>
  660. X#include <sys/socket.h>
  661. X#include <sys/un.h>
  662. X#include <sys/uio.h>
  663. X#include <errno.h>
  664. extern int errno;
  665. X#include "fmt.h"
  666. X#include "config/ptyext.h"
  667. X#include "ptycomm.h"
  668. X#include "ptymisc.h"
  669. X
  670. X/*
  671. Under most versions of SunOS and Ultrix, as well as lots of other systems,
  672. file descriptor passing doesn't work. The most important problem is that
  673. in some situations recvmsg() may return 0 without actually waiting to
  674. receive the file descriptors; in other words, msg_accrightslen may be
  675. sporadically 0. The workaround here is to pause very briefly (1/100 of a
  676. second) and try the recvmsg() again, up to 100 times. I'd prefer seeing
  677. the bug fixed.
  678. X*/
  679. X
  680. X#define ESTUPID EINPROGRESS /* [sigh] */
  681. X
  682. static int comm_path(s,ext,uid)
  683. char *s;
  684. char *ext;
  685. int uid;
  686. X{
  687. X int i;
  688. X char *t;
  689. X
  690. X/* as a last layer of protection we make sure that we only create */
  691. X/* valid filenames... */
  692. X for (i = 0;PTYEXT1[i];++i)
  693. X   if (ext[0] == PTYEXT1[i])
  694. X     break;
  695. X if (!PTYEXT1[i])
  696. X   return -1;
  697. X for (i = 0;PTYEXT2[i];++i)
  698. X   if (ext[1] == PTYEXT2[i])
  699. X     break;
  700. X if (!PTYEXT2[i])
  701. X   return -1;
  702. X t = s;
  703. X t += fmt_strncpy(t,"comm.",0);
  704. X t += fmt_uint(t,uid);
  705. X *t++ = '.';
  706. X *t++ = ext[0];
  707. X *t++ = ext[1];
  708. X *t = 0;
  709. X return 0;
  710. X}
  711. X
  712. int comm_read(ext,uid)
  713. char *ext;
  714. int uid;
  715. X{
  716. X int s;
  717. X struct sockaddr_un sa;
  718. X
  719. X if ((s = socket(AF_UNIX,SOCK_STREAM,0)) == -1)
  720. X   return -1;
  721. X sa.sun_family = AF_UNIX;
  722. X if (comm_path(sa.sun_path,ext,uid) == -1)
  723. X   return -1;
  724. X unlink(sa.sun_path);
  725. X if (bind(s,(struct sockaddr *) &sa,strlen(sa.sun_path) + 2) == -1)
  726. X   return -1;
  727. X if (listen(s,5) == -1)
  728. X   return -1;
  729. X return s;
  730. X}
  731. X
  732. int comm_accept(fd)
  733. int fd;
  734. X{
  735. X struct sockaddr_un sa;
  736. X int salen;
  737. X salen = sizeof(sa);
  738. X return accept(fd,(struct sockaddr *) &sa,&salen);
  739. X}
  740. X
  741. int comm_unlink(ext,uid)
  742. char *ext;
  743. int uid;
  744. X{
  745. X struct sockaddr_un sa;
  746. X if (comm_path(sa.sun_path,ext,uid) == -1)
  747. X   return -1;
  748. X return unlink(sa.sun_path);
  749. X}
  750. X
  751. int comm_write(ext,uid)
  752. char *ext;
  753. int uid;
  754. X{
  755. X int s;
  756. X struct sockaddr_un sa;
  757. X
  758. X if ((s = socket(AF_UNIX,SOCK_STREAM,0)) == -1)
  759. X   return -1;
  760. X sa.sun_family = AF_UNIX;
  761. X if (comm_path(sa.sun_path,ext,uid) == -1)
  762. X   return -1;
  763. X if (connect(s,(struct sockaddr *) &sa,strlen(sa.sun_path) + 2) == -1)
  764. X   return -1;
  765. X return s;
  766. X}
  767. X
  768. int csp(fdcomm,fd)
  769. int fdcomm;
  770. int fd;
  771. X{
  772. X struct msghdr msg[2];
  773. X int acc[5];
  774. X struct iovec i[2];
  775. X
  776. X msg[0].msg_name = 0;
  777. X msg[0].msg_namelen = 0;
  778. X msg[0].msg_iov = i; /* grrrr */
  779. X msg[0].msg_iovlen = 0;
  780. X msg[0].msg_accrights = (caddr_t) acc;
  781. X msg[0].msg_accrightslen = sizeof(int);
  782. X
  783. X acc[0] = fd;
  784. X
  785. X return sendmsg(fdcomm,msg,0);
  786. X}
  787. X
  788. int comm_putfd(fdcomm,fd)
  789. int fdcomm;
  790. int fd;
  791. X{
  792. X int tries;
  793. X for (tries = 0;tries < 100;++tries)
  794. X   if (csp(fdcomm,fd) == 0)
  795. X     return 0;
  796. X return -1;
  797. X}
  798. X
  799. static int cgf(fdcomm)
  800. int fdcomm;
  801. X{
  802. X struct msghdr msg[2];
  803. X int acc[5];
  804. X struct iovec i[2];
  805. X int r;
  806. X
  807. X msg[0].msg_name = 0;
  808. X msg[0].msg_namelen = 0;
  809. X msg[0].msg_iov = i; /* grrrr */
  810. X msg[0].msg_iovlen = 0;
  811. X msg[0].msg_accrights = (caddr_t) acc;
  812. X msg[0].msg_accrightslen = sizeof(int);
  813. X
  814. X do
  815. X   r = recvmsg(fdcomm,msg,0);
  816. X while ((r == -1) && ((errno == EINTR) || (errno == EWOULDBLOCK)));
  817. X if (r == -1)
  818. X   return -1;
  819. X if (msg[0].msg_accrightslen != sizeof(int))
  820. X  {
  821. X   errno = ESTUPID; /* it didn't arrive. */
  822. X   return -1;
  823. X  }
  824. X return acc[0];
  825. X}
  826. X
  827. int comm_getfd(fdcomm)
  828. int fdcomm;
  829. X{
  830. X int fd;
  831. X int tries;
  832. X
  833. X for (tries = 0;tries < 100;++tries)
  834. X  {
  835. X   fd = cgf(fdcomm);
  836. X   if (fd != -1)
  837. X     return fd;
  838. X   gaargh(10000);
  839. X  }
  840. X return -1;
  841. X}
  842. END_OF_FILE
  843. if test 3465 -ne `wc -c <'ptycomm.c'`; then
  844.     echo shar: \"'ptycomm.c'\" unpacked with wrong size!
  845. fi
  846. # end of 'ptycomm.c'
  847. fi
  848. if test -f 'ptyget.c' -a "${1}" != "-c" ; then 
  849.   echo shar: Will not clobber existing file \"'ptyget.c'\"
  850. else
  851. echo shar: Extracting \"'ptyget.c'\" \(3826 characters\)
  852. sed "s/^X//" >'ptyget.c' <<'END_OF_FILE'
  853. X#ifdef IRIS_UGH_PTYS
  854. X#include <fcntl.h>
  855. X#include <sys/types.h>
  856. X#include <sys/sysmacros.h>
  857. X#include <sys/stat.h>
  858. X#include <stdio.h>
  859. X#endif
  860. X#include <sys/file.h>
  861. X#include <errno.h>
  862. extern int errno;
  863. X#include "ptyget.h"
  864. X#include "config/ptyext.h"
  865. X#include "config/devmty.h"
  866. X#include "config/devsty.h"
  867. X#include "ptysecure.h"
  868. X
  869. static int gcd(x,y) /* assumes both nonnegative */
  870. int x; int y;
  871. X{
  872. X int t;
  873. X while (x && y) { t = x % y; x = y; y = t; }
  874. X return x ? x : y;
  875. X}
  876. X
  877. int ungetpty(fdmaster,fdslave,ext)
  878. int fdmaster;
  879. int fdslave;
  880. char *ext;
  881. X{
  882. X#ifdef IRIS_UGH_PTYS
  883. X return 0; /*XXX*/
  884. X#endif
  885. X /*XXXX*/
  886. X ptyunsecure(fdmaster,fdslave,ext);
  887. X /* XXX: close fdmaster and fdslave? nah */
  888. X}
  889. X
  890. static char fnmty[sizeof(DEVMTY) + 2] = DEVMTY;
  891. static char fnsty[sizeof(DEVSTY) + 2] = DEVSTY;
  892. X
  893. static char pty1[] = PTYEXT1;
  894. static char pty2[] = PTYEXT2;
  895. X#define pty1len (sizeof(pty1) - 1)
  896. X#define pty2len (sizeof(pty2) - 1)
  897. X
  898. static int bankok[pty1len]; /* must be initialized to 0! */
  899. X
  900. X/* not reentrant */
  901. int getfreepty(fdmaster,fdslave,ext,r1,r2,eachpty,flagxchown,allowinsecure)
  902. int *fdmaster;
  903. int *fdslave;
  904. char *ext;
  905. int r1;
  906. int r2; /* set both r1 and r2 to 0 for the standard searching order */
  907. int (*eachpty)();
  908. int flagxchown;
  909. int allowinsecure;
  910. X{
  911. X int start;
  912. X int increment;
  913. X int pos;
  914. X int p1;
  915. X int fdmty;
  916. X int fdsty;
  917. X
  918. X#ifdef IRIS_UGH_PTYS /* XXX: needless to say, deprecated */
  919. X
  920. char foo[200]; int ptynum; struct stat statmty;
  921. if (eachpty("xx") == -1) return -1;
  922. fdmty = open("/dev/ptc",O_RDWR | O_NDELAY);
  923. if (fdmty == -1) return -1;
  924. if (fstat(fdmty,&statmty) == -1) { close(fdmty); return -1; }
  925. ptynum = minor(statmty.st_rdev);
  926. sprintf(foo,"/dev/ttyq%d",ptynum);
  927. fdsty = open(foo,O_RDWR);
  928. X*fdmaster = fdmty; *fdslave = fdsty;
  929. ext[0] = 'a' + ptynum / 26;
  930. ext[1] = 'a' + ptynum % 26;
  931. return 0;
  932. X
  933. X#endif
  934. X
  935. X /* XXX: Here would be a good spot to include pty limits, say through */
  936. X /* the file PTYDIR/LIMITS. Lines of the form user group num, saying */
  937. X /* that user in that group is limited to num ptys, with * for all. */
  938. X /* All pty use would have to be logged somewhere. Anyway, with a */
  939. X /* streams-based pty, there wouldn't be much point to limits. */
  940. X
  941. X pos = pty1len * pty2len;
  942. X start = r1 % pos; if (start < 0) start += pos;
  943. X increment = r2 % pos; if (increment < 0) increment += pos;
  944. X
  945. X while (gcd(increment,pos) != 1)
  946. X   ++increment; /* note that this weights some increments more heavily */
  947. X fnmty[sizeof(DEVMTY) + 1] = 0;
  948. X fnsty[sizeof(DEVSTY) + 1] = 0;
  949. X
  950. X pos = start;
  951. X do
  952. X  {
  953. X   p1 = pos / pty2len;
  954. X   fnmty[sizeof(DEVMTY) - 1] = pty1[p1];
  955. X   if (!bankok[p1])
  956. X    {
  957. X     fnmty[sizeof(DEVMTY)] = pty2[0];
  958. X     if (access(fnmty,F_OK) == -1)
  959. X       bankok[p1] = -1;
  960. X     else
  961. X       bankok[p1] = 1;
  962. X    }
  963. X   if (bankok[p1] == 1) /* okay, we know bank exists. */
  964. X    {
  965. X     fnsty[sizeof(DEVMTY)] = fnmty[sizeof(DEVMTY)] = pty2[pos % pty2len];
  966. X     fnsty[sizeof(DEVSTY) - 1] = pty1[p1];
  967. X     if (eachpty(fnmty + sizeof(DEVMTY) - 1) == -1)
  968. X       return -1;
  969. X     do
  970. X       fdmty = open(fnmty,O_RDWR);
  971. X     while ((fdmty == -1) && (errno == EINTR));
  972. X     if (fdmty != -1)
  973. X      {
  974. X       do
  975. X         fdsty = open(fnsty,O_RDWR);
  976. X       while ((fdsty == -1) && (errno == EINTR));
  977. X       if (fdsty == -1)
  978. X     close(fdmty); /* XXX: warning that slave isn't openable? */
  979. X       else
  980. X    {
  981. X     setnonblock(fdmty); /*XXX*/
  982. X     ext[0] = pty1[p1];
  983. X     ext[1] = pty2[pos % pty2len];
  984. X     /* Got both sides of the tty open! Now comes the tricky part. */
  985. X     if (ptysecure(&fdmty,&fdsty,ext,fnmty,fnsty,flagxchown,allowinsecure) == -1)
  986. X      {
  987. X       /* XXX: warning of security violation? */
  988. X      }
  989. X     else
  990. X      {
  991. X       unsetnonblock(fdmty); /*XXX*/
  992. X       /* It's ours. */
  993. X       *fdmaster = fdmty;
  994. X       *fdslave = fdsty;
  995. X       return 0;
  996. X      }
  997. X    }
  998. X      }
  999. X    }
  1000. X   pos = (pos + increment) % (pty1len * pty2len);
  1001. X  }
  1002. X while (pos != start);
  1003. X
  1004. X return -1; /* all unopenable? yikes */
  1005. X}
  1006. END_OF_FILE
  1007. if test 3826 -ne `wc -c <'ptyget.c'`; then
  1008.     echo shar: \"'ptyget.c'\" unpacked with wrong size!
  1009. fi
  1010. # end of 'ptyget.c'
  1011. fi
  1012. if test -f 'ptyslave.c' -a "${1}" != "-c" ; then 
  1013.   echo shar: Will not clobber existing file \"'ptyslave.c'\"
  1014. else
  1015. echo shar: Extracting \"'ptyslave.c'\" \(2764 characters\)
  1016. sed "s/^X//" >'ptyslave.c' <<'END_OF_FILE'
  1017. X#include <signal.h>
  1018. X#include <sys/types.h>
  1019. X#include <sys/file.h>
  1020. X#include "fmt.h"
  1021. X#include "ptyerr.h"
  1022. X#include "ptyslave.h"
  1023. X#include "ralloc.h"
  1024. X
  1025. void slave(fdsty,ext,program,flagxerrwo,flagsameerr,uid,flagverbose,flagxexcl)
  1026. int fdsty;
  1027. char *ext;
  1028. char **program;
  1029. int flagxerrwo;
  1030. int flagsameerr;
  1031. int uid;
  1032. int flagverbose;
  1033. int flagxexcl;
  1034. X{
  1035. X char ptyext[10];
  1036. X int fdout;
  1037. X int fdtty;
  1038. X char *t;
  1039. X
  1040. X /* we're already dissociated and reassociated */
  1041. X close(0);
  1042. X close(1);
  1043. X if (flagsameerr < 2)
  1044. X   close(2);
  1045. X if (flagsameerr < 1)
  1046. X  {
  1047. X   close(3);
  1048. X   for (fdout = getdtablesize();fdout > 3;--fdout)
  1049. X     if (fdout != fdsty)
  1050. X       close(fdout);
  1051. X  }
  1052. X if (dup(fdsty) != 0)
  1053. X  {
  1054. X   warn("fatal","cannot dup slave tty descriptor");
  1055. X   die(1);
  1056. X  }
  1057. X if (dup(fdsty) != 1)
  1058. X  {
  1059. X   warn("fatal","cannot dup slave tty descriptor");
  1060. X   die(1);
  1061. X  }
  1062. X if (flagsameerr < 2)
  1063. X   if (dup(fdsty) != 2) /* XXX: what about flagxerrwo? */
  1064. X    {
  1065. X     warn("fatal","cannot dup slave tty descriptor");
  1066. X     die(1);
  1067. X    }
  1068. X if (flagsameerr < 1)
  1069. X   if (open("/dev/tty",O_RDWR) != 3)
  1070. X    {
  1071. X     warn("fatal","cannot open /dev/tty under pseudo-tty");
  1072. X     die(1);
  1073. X    }
  1074. X close(fdsty);
  1075. X
  1076. X if ((fdtty = open("/dev/tty",O_RDWR)) == -1)
  1077. X  {
  1078. X   warn("fatal","cannot open /dev/tty second time under pseudo-tty");
  1079. X   die(1);
  1080. X  }
  1081. X if (flagxexcl)
  1082. X   if (tty_setexcl(0) == -1)
  1083. X     warn("warning","cannot set exclusive use on pseudo-tty");
  1084. X if (setpgrp(0,getpid()) == -1)
  1085. X  {
  1086. X   warn("fatal","cannot setpgrp");
  1087. X   die(1);
  1088. X  }
  1089. X signal(SIGTTOU,SIG_IGN);
  1090. X if (tctpgrp(fdtty,getpid()) == -1)
  1091. X  {
  1092. X   warn("warning","cannot set pseudo-tty pgrp");
  1093. X   /* XXX: this always seems to happen on an IRIS. why? */
  1094. X  }
  1095. X signal(SIGTTOU,SIG_DFL);
  1096. X /* pty modes are already set */
  1097. X /* pty inode protection, including chmod and chown, is done */
  1098. X close(fdtty);
  1099. X
  1100. X /* logs, including utmp and wtmp, are already set up */
  1101. X
  1102. X /* master's comm file is already set up. end of that race! */
  1103. X
  1104. X if (setreuid(uid,uid) == -1)
  1105. X   /* This syscall shouldn't ever fail, so most programs don't check it. */
  1106. X   /* But we absolutely refuse to exec while setuid. */
  1107. X  {
  1108. X   warn("fatal","cannot setreuid");
  1109. X   die(1);
  1110. X  }
  1111. X
  1112. X t = ptyext;
  1113. X t += fmt_strncpy(ptyext,"PTY=",0);
  1114. X *t++ = ext[0];
  1115. X *t++ = ext[1];
  1116. X *t = 0;
  1117. X if (env_put(ptyext) == -1)
  1118. X  {
  1119. X   warn("fatal","cannot set up PTY in environment");
  1120. X   die(1);
  1121. X  }
  1122. X
  1123. X sigsetmask(0); /*XXX: restore exactly? */
  1124. X
  1125. X if (flagverbose > 1)
  1126. X   warn("executing program",program[0]);
  1127. X execvp(program[0],program);
  1128. X  
  1129. X  {
  1130. X   char *buf;
  1131. X   buf = ralloc(strlen(program) + 30);
  1132. X   if (!buf)
  1133. X     warn("fatal","cannot exec");
  1134. X   else
  1135. X    {
  1136. X     t = buf;
  1137. X     t += fmt_strncpy(t,"cannot exec ",0);
  1138. X     t += fmt_strncpy(t,program[0],0);
  1139. X     *t = 0;
  1140. X     warn("fatal",buf);
  1141. X     rfree(buf);
  1142. X    }
  1143. X  }
  1144. X die(1);
  1145. X /*NOTREACHED*/
  1146. X}
  1147. END_OF_FILE
  1148. if test 2764 -ne `wc -c <'ptyslave.c'`; then
  1149.     echo shar: \"'ptyslave.c'\" unpacked with wrong size!
  1150. fi
  1151. # end of 'ptyslave.c'
  1152. fi
  1153. if test -f 'ptytexts.c' -a "${1}" != "-c" ; then 
  1154.   echo shar: Will not clobber existing file \"'ptytexts.c'\"
  1155. else
  1156. echo shar: Extracting \"'ptytexts.c'\" \(3662 characters\)
  1157. sed "s/^X//" >'ptytexts.c' <<'END_OF_FILE'
  1158. X#include "ptytexts.h"
  1159. X
  1160. char *ptyauthor = "\
  1161. pty was written by Daniel J. Bernstein.\n\
  1162. Internet address: brnstnd@nyu.edu.\n\
  1163. X" ;
  1164. X
  1165. char *ptyversion = "\
  1166. pty version 4.0, February 9, 1992.\n\
  1167. Copyright (c) 1992, Daniel J. Bernstein.\n\
  1168. All rights reserved.\n\
  1169. X" ;
  1170. X
  1171. char *ptycopyright = "\
  1172. pty version 4.0, February 9, 1992.\n\
  1173. Copyright (c) 1992, Daniel J. Bernstein.\n\
  1174. All rights reserved.\n\
  1175. X\n\
  1176. I want this program to be distributed freely in original form.\n\
  1177. X\n\
  1178. Once you've received a legal copy of this program, you can use it.\n\
  1179. XForever. Nobody can take that right away from you. You can make changes\n\
  1180. and backup copies for your use (or, if you're an organization, for the\n\
  1181. use of everyone in the organization). You can distribute patches (though\n\
  1182. not patched versions). You'd have all these rights even if I didn't tell\n\
  1183. you about them.\n\
  1184. X\n\
  1185. I do grant you further rights, as detailed in the source package. Don't\n\
  1186. worry about them unless you're planning to distribute further copies.\n\
  1187. X\n\
  1188. If you have questions about this program or about this notice, or if you\n\
  1189. would like additional rights beyond those granted above, or if you have\n\
  1190. a patch that you don't mind sharing, please contact me on the Internet\n\
  1191. at brnstnd@nyu.edu.\n\
  1192. X" ;
  1193. X
  1194. char *ptywarranty = "\
  1195. Daniel J. Bernstein disclaims all warranties to the extent permitted\n\
  1196. by applicable law. He is not and shall not be liable for any damages\n\
  1197. arising from the use of this program. This disclaimer shall be governed\n\
  1198. by the laws of the state of New York.\n\
  1199. X\n\
  1200. In other words, use this program at your own risk.\n\
  1201. X\n\
  1202. If you have questions about this program or about this disclaimer of\n\
  1203. warranty, please contact me on the Internet at brnstnd@nyu.edu.\n\
  1204. X" ;
  1205. X
  1206. char *ptyusage = "\
  1207. Usage: pty [ -qQve3EdDjJsStTrR0ACHUVW ] [ -h host ] [ -O remote ]\n\
  1208. X           [ -p[cCdDeEnNrRsS780] ] [ -x[cCeEfFrRsSiuUwWxX] ] program [ arg... ]\n\
  1209. Help:  pty -H\n\
  1210. X" ;
  1211. X
  1212. char *ptyhelp = "\
  1213. pty runs a program under a pseudo-terminal session.\n\
  1214. pty -ACHUVW: print authorship notice, copyright notice, this notice,\n\
  1215. X             short usage summary, version number, disclaimer of warranty\n\
  1216. pty [-qQve3EdDjJsStTrR0] [-p[cCdDeEnNrRsS780]] [-x[cCeEfFrRsSiuUwWxX]] [-hhost]\n\
  1217. X    [-O remote] program [arg...]: run program under a pseudo-terminal\n\
  1218. Options processed l to r. Capitals turn things off. Here + means default.\n\
  1219. X-q: quiet (nothing on stderr)   -e: leave fds 2 & 3    d=>T  s=>E  R=>T\n\
  1220. X+Q: normal level of verbosity   -3: leave fd 3 only    d=dJT D=Djt 0=eSTp0\n\
  1221. X-v: complain about everything   +E: 2 & 3 both->pty    s=sxu S=SxU p0=pcrEND\n\
  1222. X-d: we are detached    +j: job control    +t: change orig tty to char mode\n\
  1223. X+D: we have ctrl tty   -J: ignore stops   -T: leave orig tty alone\n\
  1224. X-s: session (allow disconnect & reconnect)   +r: read input\n\
  1225. X+S: no session: disconnect will send HUP     -R: output only (like rsh -n)\n\
  1226. X-h host: use host in utmp/wtmp  -O remote: use remote in sclog\n\
  1227. X-p[cCdDeEnNrRsS78]: set pty modes; defaults taken from original tty if -D\n\
  1228. X  c: cbreak, character mode  +n: change return to newline  +e: echo\n\
  1229. X +d: new line discipline      r: raw, no keyboard signals  +s: screen, crt\n\
  1230. X-x[cCeEfFrRsSiuUwWxX]: security/experimental/extended, may be restricted\n\
  1231. X  c: chown pty  e: pty's stderr wronly  f: FIONREAD flow-control  i: insecure\n\
  1232. X +r: random pty  w: /usr/adm/wtmp  u: /etc/utmp  x: TIOCEXCL  s: extra-secure\n\
  1233. If you have questions about or suggestions for pty, please feel free\n\
  1234. to contact the author, Daniel J. Bernstein, at brnstnd@nyu.edu\n\
  1235. on the Internet.\n\
  1236. X" ;
  1237. X/* ptyhelp *still* fits. Incredible. :-) */
  1238. END_OF_FILE
  1239. if test 3662 -ne `wc -c <'ptytexts.c'`; then
  1240.     echo shar: \"'ptytexts.c'\" unpacked with wrong size!
  1241. fi
  1242. # end of 'ptytexts.c'
  1243. fi
  1244. if test -f 'radixsort.3' -a "${1}" != "-c" ; then 
  1245.   echo shar: Will not clobber existing file \"'radixsort.3'\"
  1246. else
  1247. echo shar: Extracting \"'radixsort.3'\" \(2915 characters\)
  1248. sed "s/^X//" >'radixsort.3' <<'END_OF_FILE'
  1249. X.TH radixsort 3
  1250. X.SH NAME
  1251. radixsort \- fast in-memory string sort
  1252. X.SH SYNTAX
  1253. X.B #include <radixsort.h>
  1254. X
  1255. int \fBradixsort7(\fIbase,n,endchar,table,index,ualloc,ufree\fB)\fR
  1256. X
  1257. int \fBradixsort5(\fIbase,n,endchar,table,index\fB)\fR
  1258. X
  1259. int \fBradixsort4(\fIbase,n,endchar,table\fB)\fR
  1260. X
  1261. int \fBradixsort3(\fIbase,n,endchar\fB)\fR
  1262. X
  1263. unsigned char \fI**base\fR;
  1264. X.br
  1265. int \fIn\fR;
  1266. X.br
  1267. unsigned int \fIendchar\fR;
  1268. X.br
  1269. unsigned char \fI*table\fR;
  1270. X.br
  1271. int \fIindex\fR;
  1272. X.br
  1273. char \fI*(*ualloc)()\fR;
  1274. X.br
  1275. void \fI(*ufree)()\fR;
  1276. X.SH DESCRIPTION
  1277. X.B radixsort7
  1278. is a modified radix sort.
  1279. It sorts an array,
  1280. X.I base,
  1281. of pointers to unsigned character strings.
  1282. X.I base
  1283. contains
  1284. X.I n
  1285. pointers.
  1286. The strings are terminated by
  1287. X.I (unsigned char) endchar
  1288. and may contain any other characters.
  1289. X
  1290. X.B radixsort7
  1291. allocates some temporary workspace
  1292. using
  1293. X.I ualloc
  1294. and
  1295. X.I ufree,
  1296. which must provide the same interface as
  1297. X.B malloc
  1298. and
  1299. X.B free.
  1300. X.B radixsort5
  1301. is the same as
  1302. X.B radixsort7
  1303. but with the default
  1304. X.B malloc
  1305. and
  1306. X.B free.
  1307. X
  1308. X.B radixsort7
  1309. sorts the array
  1310. by lexical ASCII order of the strings,
  1311. with
  1312. X.I (unsigned char) endchar
  1313. considered smaller than any other character.
  1314. If
  1315. X.I index
  1316. is greater than zero,
  1317. the first
  1318. X.I index
  1319. characters of each string are ignored,
  1320. and sorting is based on the characters following.
  1321. In other words, each pointer in
  1322. X.I base
  1323. is shifted by
  1324. X.I index.
  1325. This is useful for applications which want to store
  1326. additional data in the first few bytes of each string.
  1327. X.B radixsort4
  1328. is the same as
  1329. X.B radixsort5
  1330. with
  1331. X.I index
  1332. set to 0.
  1333. X
  1334. X.I table
  1335. provides more flexibility in the sort order.
  1336. If it
  1337. is non-zero,
  1338. it must point to an array of
  1339. UCHAR_MAX + 1 (i.e., the character set size, typically 256)
  1340. unsigned characters
  1341. containing the sort weight of each possible character in
  1342. the strings.
  1343. X.I endchar
  1344. is ignored;
  1345. instead,
  1346. every character with sort weight 0
  1347. in
  1348. X.I table
  1349. is considered a terminator.
  1350. Any number of bytes can have the same sort weight;
  1351. if, for instance, the table gives a-z the same weights as A-Z,
  1352. X.B radixsort7
  1353. will perform a case-insensitive sort.
  1354. X.B radixsort3
  1355. is the same as
  1356. X.B radixsort4
  1357. without a
  1358. X.I table.
  1359. X
  1360. X.B radixsort7
  1361. is stable: if two strings are equal, their pointers will
  1362. remain in the same order in the sorted array.
  1363. X.B radixsort7
  1364. takes time
  1365. at worst
  1366. proportional to the total number of
  1367. characters (including terminators) in the strings.
  1368. This is within a constant factor of the
  1369. information-theoretic optimum. In practice,
  1370. X.B radixsort7
  1371. is extremely fast.
  1372. X
  1373. X.B radixsort7
  1374. returns 0 normally,
  1375. X\-1 upon a memory allocation failure.
  1376. X
  1377. X.B radixsort(\fIbase,n,table,endchar\fB)
  1378. is the same as
  1379. X.B radixsort4(\fIbase,n,endchar,table\fB).
  1380. It is deprecated.
  1381. It is included here only for compatibility with BSD 4.4.
  1382. X
  1383. X.B radixsort7
  1384. and its variants
  1385. are
  1386. X.B not
  1387. safe to use inside signal handlers.
  1388. X.SH VERSION
  1389. radixsort/DJB 3.0, 7/23/91.
  1390. X.SH AUTHORS
  1391. Daniel J. Bernstein
  1392. and
  1393. Keith Bostic.
  1394. X.SH "SEE ALSO"
  1395. sort(1),
  1396. qsort(3)
  1397. END_OF_FILE
  1398. if test 2915 -ne `wc -c <'radixsort.3'`; then
  1399.     echo shar: \"'radixsort.3'\" unpacked with wrong size!
  1400. fi
  1401. # end of 'radixsort.3'
  1402. fi
  1403. if test -f 'ralloc.c' -a "${1}" != "-c" ; then 
  1404.   echo shar: Will not clobber existing file \"'ralloc.c'\"
  1405. else
  1406. echo shar: Extracting \"'ralloc.c'\" \(3779 characters\)
  1407. sed "s/^X//" >'ralloc.c' <<'END_OF_FILE'
  1408. X/* ralloc.c, ralloc.h: recovering alloc
  1409. Daniel J. Bernstein, brnstnd@nyu.edu.
  1410. Depends on sod.h.
  1411. Requires malloc/free.
  1412. X8/26/91: Changed exit() to _exit().
  1413. X8/26/91: Made rallocneverfail() overwrite any previous handler.
  1414. X7/24/91: Added rallocneverfail().
  1415. X7/18/91: Baseline. ralloc 1.0, public domain.
  1416. No known patent problems.
  1417. X
  1418. Lots of library routines allocate space for temporary objects: compiled
  1419. regular expressions, for example. They don't destroy the objects between
  1420. each call---wouldn't it be a waste to reallocate and recompile those
  1421. regular expressions on every single pattern match? But when space gets
  1422. tight, you don't want all those temporary objects cluttering the heap.
  1423. You've got to deallocate them as soon as possible. Sure, library X might
  1424. have some deallocation routines---but if X is hidden below library Y and
  1425. separate library A runs out of space, do you expect A to know about X
  1426. and call X's routines? Of course not. How can A and X coordinate?
  1427. X
  1428. The solution is ralloc. ralloc works just like malloc, except that when
  1429. it runs out of memory, it tries to recover space from anyone who's
  1430. willing to give a little slack. If f is a deallocation function, you can
  1431. call rallocinstall(f), and ralloc(n) will call f() if there aren't n
  1432. bytes free. f() should return a non-zero integer if it could free some
  1433. memory, 0 if not. Several libraries can rallocinstall their deallocation
  1434. routines, and ralloc will cycle between all of them. Make sure that f
  1435. actually frees some memory if it returns non-zero---otherwise ralloc()
  1436. will loop, trying f again and again and wondering why malloc() never has
  1437. enough space. (In a future implementation I might add a loop counter and
  1438. have ralloc give up after trying f enough times.)
  1439. X
  1440. According to John F. Haugh, ralloc is a Bad Thing, because it inherently
  1441. requires static variables, hence can't be put into a ``pure'' shared
  1442. library. Face it, John: ralloc() solves a real problem, and if you can't
  1443. put it in a shared library, it's not because ralloc() is somehow evil.
  1444. It's because your shared libraries aren't good enough.
  1445. X
  1446. X*/
  1447. X
  1448. X#include "ralloc.h"
  1449. X#include "sod.h"
  1450. extern char *malloc(); /*XXXX*/
  1451. extern void free();
  1452. X
  1453. typedef int (*foo)();
  1454. X
  1455. SODdecl(funlist,foo);
  1456. X
  1457. static funlist funhead = 0;
  1458. static funlist funlast = 0; /* last fun to successfully recover */
  1459. X
  1460. static int ralloccount = 0;
  1461. X
  1462. int rcount()
  1463. X{
  1464. X return ralloccount;
  1465. X}
  1466. X
  1467. void rfree(s)
  1468. char *s;
  1469. X{
  1470. X /* This is for completeness, and for another reason: so that you only */
  1471. X /* have to modify this file if you want a debugging malloc-free. */
  1472. X --ralloccount; /* for instance */
  1473. X free(s);
  1474. X}
  1475. X
  1476. static int crit = 0; /* just to be safe */
  1477. X
  1478. static int (*neverfail)() = 0;
  1479. X
  1480. static void die(n)
  1481. unsigned n;
  1482. X{
  1483. X if (neverfail)
  1484. X   neverfail(n);
  1485. X _exit(1); /*XXX*/
  1486. X}
  1487. X
  1488. char *ralloc(n)
  1489. unsigned n;
  1490. X{
  1491. X char *t;
  1492. X funlist fun;
  1493. X
  1494. X if(t = malloc(n))
  1495. X  {
  1496. X   ++ralloccount;
  1497. X   return t;
  1498. X  }
  1499. X if (crit)
  1500. X   if (neverfail)
  1501. X     die(n);
  1502. X   else
  1503. X     return 0;
  1504. X if (!funhead)
  1505. X   if (neverfail)
  1506. X     die(n);
  1507. X   else
  1508. X     return 0;
  1509. X crit = 1;
  1510. X fun = (funlast ? SODnext(funlast) : funhead);
  1511. X do
  1512. X  {
  1513. X   if(!fun)
  1514. X     fun = funhead;
  1515. X   if((*SODdata(fun))()) /* XXX: can we make use of args or return code? */
  1516. X     funlast = fun;
  1517. X   else
  1518. X     if(fun == funlast)
  1519. X      {
  1520. X       crit = 0;
  1521. X       if (neverfail)
  1522. X     die(n);
  1523. X       else
  1524. X         return 0; /* gaack! */
  1525. X      }
  1526. X   fun = SODnext(fun);
  1527. X   t = malloc(n);
  1528. X  }
  1529. X while(!t);
  1530. X ++ralloccount;
  1531. X crit = 0;
  1532. X return t;
  1533. X}
  1534. X
  1535. void rallocneverfail(f)
  1536. int (*f)();
  1537. X{
  1538. X neverfail = f; /* possibly overwriting previous handler */
  1539. X}
  1540. X
  1541. X#define malloc ralloc
  1542. X
  1543. int rallocinstall(f)
  1544. int (*f)();
  1545. X{
  1546. X funlist fun;
  1547. X
  1548. X fun = SODalloc(funlist,fun,ralloc);
  1549. X if(!fun)
  1550. X   return -1;
  1551. X SODdata(fun) = f;
  1552. X SODpush(funhead,fun);
  1553. X
  1554. X funlast = funhead; /* need to set it to something */
  1555. X
  1556. X return 0;
  1557. X}
  1558. END_OF_FILE
  1559. if test 3779 -ne `wc -c <'ralloc.c'`; then
  1560.     echo shar: \"'ralloc.c'\" unpacked with wrong size!
  1561. fi
  1562. # end of 'ralloc.c'
  1563. fi
  1564. if test -f 'sesslist.c' -a "${1}" != "-c" ; then 
  1565.   echo shar: Will not clobber existing file \"'sesslist.c'\"
  1566. else
  1567. echo shar: Extracting \"'sesslist.c'\" \(3693 characters\)
  1568. sed "s/^X//" >'sesslist.c' <<'END_OF_FILE'
  1569. X/* XXX: this sort of depends on the dirent interface */
  1570. X#undef POSIX /* JIC XXX */
  1571. X#include <sys/types.h>
  1572. X#include <sys/file.h>
  1573. X#include <sys/dir.h>
  1574. X#include <stdio.h>
  1575. X#include "config/ptydir.h"
  1576. X#include "config/ptylongname.h"
  1577. X#include "fmt.h"
  1578. X#include "scan.h"
  1579. X#include "getopt.h"
  1580. X#include "ptycomm.h"
  1581. X
  1582. main(argc,argv)
  1583. int argc;
  1584. char *argv[];
  1585. X{
  1586. X int uid;
  1587. X DIR *dirp;
  1588. X struct direct *dp;
  1589. X int opt;
  1590. X char sep;
  1591. X int flagall;
  1592. X
  1593. X uid = getuid();
  1594. X sep = '\n';
  1595. X flagall = 0;
  1596. X
  1597. X while ((opt = getopt(argc,argv,"0a")) != opteof)
  1598. X   switch(opt)
  1599. X    {
  1600. X     case 'a':
  1601. X       flagall = 1;
  1602. X       break;
  1603. X     case '0':
  1604. X       sep = 0;
  1605. X       break;
  1606. X     case '?':
  1607. X     default:
  1608. X       exit(1);
  1609. X    }
  1610. X argc -= optind; argv += optind;
  1611. X
  1612. X if (chdir(PTYDIR) == -1)
  1613. X  {
  1614. X   fprintf(stderr,"%s: fatal: cannot change to session directory %s\n",optprogname,PTYDIR);
  1615. X   exit(2);
  1616. X  }
  1617. X
  1618. X dirp = opendir(".");
  1619. X while (dp = readdir(dirp))
  1620. X  {
  1621. X   unsigned int duid;
  1622. X   char dext[2];
  1623. X   char *t;
  1624. X   unsigned int len;
  1625. X
  1626. X   t = dp->d_name;
  1627. X   len = scan_strncmp(t,"comm.",5);
  1628. X   if (len < 5)
  1629. X     ; /*XXX*/
  1630. X   t += len;
  1631. X   len = scan_uint(t,&duid);
  1632. X   if (len < 1)
  1633. X     ; /*XXX*/
  1634. X   t += len;
  1635. X   len = scan_strncmp(t,".",1);
  1636. X   if (len < 1)
  1637. X     ; /*XXX*/
  1638. X   t += len;
  1639. X   dext[0] = *t;
  1640. X   if (dext[0])
  1641. X     dext[1] = *++t;
  1642. X   else
  1643. X     dext[1] = 0;
  1644. X
  1645. X   if ((duid == uid) || (flagall && !uid)) /*XXXX*/
  1646. X    {
  1647. X     int fdcomm;
  1648. X     int mslavepid;
  1649. X     int mpid;
  1650. X     char mrecoext[2];
  1651. X     char resp6[6];
  1652. X     int mflagsession;
  1653. X     char mlongname[PTYLONGNAMELEN];
  1654. X     static char outbuf[PTYLONGNAMELEN + 200];
  1655. X     char mext[2];
  1656. X     int mconn;
  1657. X     char *t;
  1658. X
  1659. X#define DO6 read(fdcomm,resp6,6);
  1660. X#define BUMMER { close(fdcomm); continue; }
  1661. X
  1662. X     fdcomm = comm_write(dext,uid);
  1663. X     if (fdcomm == -1)
  1664. X       continue;
  1665. X     if (write(fdcomm,"a",1) < 1)
  1666. X       BUMMER
  1667. X     DO6
  1668. X     if (write(fdcomm,"e",1) < 1)
  1669. X       BUMMER
  1670. X     if (read(fdcomm,mext,2) < 2)
  1671. X       BUMMER
  1672. X     if (write(fdcomm,"l",1) < 1)
  1673. X       BUMMER
  1674. X     DO6
  1675. X     if (!respeq(resp6,"longnm"))
  1676. X       BUMMER
  1677. X     if (read(fdcomm,mlongname,sizeof(mlongname)) < sizeof(mlongname))
  1678. X       BUMMER
  1679. X     if (write(fdcomm,"C",1) < 1)
  1680. X       BUMMER
  1681. X     DO6
  1682. X     mconn = respeq(resp6,"owuno?");
  1683. X     if (write(fdcomm,"p",1) < 1)
  1684. X       BUMMER
  1685. X     if (read(fdcomm,&mpid,sizeof(mpid)) < sizeof(mpid))
  1686. X       BUMMER
  1687. X     if (write(fdcomm,"P",1) < 1)
  1688. X       BUMMER
  1689. X     if (read(fdcomm,&mslavepid,sizeof(mslavepid)) < sizeof(mslavepid))
  1690. X       BUMMER
  1691. X     if (write(fdcomm,"D",1) < 1)
  1692. X       BUMMER
  1693. X     if (read(fdcomm,&mflagsession,sizeof(mflagsession)) < sizeof(mflagsession))
  1694. X       BUMMER
  1695. X     if (write(fdcomm,"S",1) < 1)
  1696. X       BUMMER
  1697. X     DO6
  1698. X     if (!respeq(resp6,"latest"))
  1699. X       BUMMER
  1700. X     if (read(fdcomm,mrecoext,2) < 2)
  1701. X       BUMMER
  1702. X     close(fdcomm);
  1703. X
  1704. X     if ((mext[0] != dext[0]) || (mext[1] != dext[1]))
  1705. X       ; /* better to report what the master says */
  1706. X
  1707. X     t = outbuf;
  1708. X     if (!mflagsession) t += fmt_strncpy(t,"non-",0);
  1709. X     t += fmt_strncpy(t,"session ",0);
  1710. X     *t++ = mext[0];
  1711. X     *t++ = mext[1];
  1712. X     t += fmt_strncpy(t," pid ",0);
  1713. X     t += fmt_uint(t,mpid);
  1714. X     t += fmt_strncpy(t," slave ",0);
  1715. X     t += fmt_uint(t,mslavepid);
  1716. X     if (mflagsession)
  1717. X      {
  1718. X       *t++ = ' ';
  1719. X       if (!mconn) t += fmt_strncpy(t,"dis",0);
  1720. X       t += fmt_strncpy(t,"connected",0);
  1721. X      }
  1722. X     if (mrecoext[0])
  1723. X      {
  1724. X       t += fmt_strncpy(t," (will drop into ",0);
  1725. X       *t++ = mrecoext[0];
  1726. X       *t++ = mrecoext[1];
  1727. X       *t++ = ')';
  1728. X      }
  1729. X     if (mlongname[0])
  1730. X      {
  1731. X       *t++ = ':';
  1732. X       *t++ = ' ';
  1733. X       t += fmt_strncpy(t,mlongname,0);
  1734. X      }
  1735. X     *t++ = sep;
  1736. X
  1737. X     fwrite(outbuf,1,t - outbuf,stdout);
  1738. X    }
  1739. X  }
  1740. X exit(0);
  1741. X}
  1742. END_OF_FILE
  1743. if test 3693 -ne `wc -c <'sesslist.c'`; then
  1744.     echo shar: \"'sesslist.c'\" unpacked with wrong size!
  1745. fi
  1746. # end of 'sesslist.c'
  1747. fi
  1748. if test -f 'sessmenu.c' -a "${1}" != "-c" ; then 
  1749.   echo shar: Will not clobber existing file \"'sessmenu.c'\"
  1750. else
  1751. echo shar: Extracting \"'sessmenu.c'\" \(3293 characters\)
  1752. sed "s/^X//" >'sessmenu.c' <<'END_OF_FILE'
  1753. X#include <stdio.h>
  1754. extern char *malloc();
  1755. X
  1756. static char crterase[3] = { 8, ' ', 8 };
  1757. X
  1758. main(argc,argv,envp)
  1759. int argc;
  1760. char *argv[];
  1761. char *envp[];
  1762. X{
  1763. X int flagecho;
  1764. X int flagdisc;
  1765. X int flagseveral;
  1766. X FILE *fi;
  1767. X int ch;
  1768. X char okext1;
  1769. X char okext2;
  1770. X char ext1;
  1771. X char ext2;
  1772. X int i;
  1773. X char cmd[200];
  1774. X char **newargv;
  1775. X
  1776. X flagdisc = 0;
  1777. X flagseveral = 0;
  1778. X flagecho = 1;
  1779. X
  1780. X fi = popen("sesslist -0","r");
  1781. X if (fi)
  1782. X  {
  1783. X   while ((ch = getc(fi)) != EOF)
  1784. X    {
  1785. X     if (ch == 's')
  1786. X      {
  1787. X       while (((ch = getc(fi)) != EOF) && (ch != ' '))
  1788. X     ;
  1789. X       if (ch == EOF) break;
  1790. X       if ((ch = getc(fi)) == EOF) break; ext1 = ch;
  1791. X       if ((ch = getc(fi)) == EOF) break; ext2 = ch;
  1792. X       for (i = 0;i < 5;++i)
  1793. X    {
  1794. X     while (((ch = getc(fi)) != EOF) && (ch != ' '))
  1795. X       ;
  1796. X     if (ch == EOF) break;
  1797. X    }
  1798. X       if (ch == EOF) break;
  1799. X       if ((ch = getc(fi)) != 'd') goto breakif;
  1800. X
  1801. X       /* Now ext1 and ext2 give a disconnected session. */
  1802. X       if (flagdisc)
  1803. X     flagseveral = 1;
  1804. X       else
  1805. X         flagdisc = 1;
  1806. X       okext1 = ext1;
  1807. X       okext2 = ext2;
  1808. X       printf("You have a disconnected session on /dev/tty%c%c, with these processes:\r\n",ext1,ext2); fflush(stdout);
  1809. X       sprintf(cmd,"ps augxt%c%c | sed 's/$/\r/'",ext1,ext2);
  1810. X       system(cmd);
  1811. X       while (((ch = getc(fi)) != EOF) && (ch != 'd'))
  1812. X     ;
  1813. X       if ((ch = getc(fi)) == ':')
  1814. X    {
  1815. X     printf("Session %c%c is named:",ext1,ext2); fflush(stdout);
  1816. X     while (((ch = getc(fi)) != EOF) && ch)
  1817. X       putchar(ch);
  1818. X     printf(".\r\n"); fflush(stdout);
  1819. X    }
  1820. X      }
  1821. X     breakif: ;
  1822. X     if (ch == EOF) break;
  1823. X     if (ch)
  1824. X       while (((ch = getc(fi)) != EOF) && ch)
  1825. X         ;
  1826. X     if (ch == EOF) break;
  1827. X    }
  1828. X   pclose(fi); /* XXX: or maybe it's not worth waiting? */
  1829. X  }
  1830. X
  1831. X if (flagdisc)
  1832. X  {
  1833. X   char r1;
  1834. X   char r2;
  1835. X   int pos;
  1836. X   char ch;
  1837. X
  1838. X   if (flagseveral)
  1839. X     sprintf(cmd,"\
  1840. Would you like to reconnect to one of those sessions?\r\n\
  1841. If so, type its two-character extension, like %c%c for the last one.\r\n\
  1842. To instead start a new session as usual, just press return: ",okext1,okext2);
  1843. X   else
  1844. X     sprintf(cmd,"\
  1845. Would you like to reconnect to that session?\r\n\
  1846. If so, type its two-character extension, %c%c.\r\n\
  1847. To instead start a new session as usual, just press return: ",okext1,okext2);
  1848. X   write(1,cmd,strlen(cmd));
  1849. X
  1850. X   pos = 0;
  1851. X   while (read(0,&ch,1) == 1)
  1852. X    {
  1853. X     if ((ch == 8) || (ch == 127))
  1854. X      {
  1855. X       if (pos)
  1856. X    {
  1857. X     --pos;
  1858. X         if (flagecho)
  1859. X           write(1,crterase,3);
  1860. X    }
  1861. X       continue;
  1862. X      }
  1863. X     if ((ch == 10) || (ch == 13))
  1864. X      {
  1865. X       if (flagecho)
  1866. X     write(1,"\r\n",2);
  1867. X       if (pos < 2)
  1868. X     break;
  1869. X       sprintf(cmd,"exec pty -d reconnect %c%c",r1,r2);
  1870. X       execl("/bin/sh","sh","-c",cmd,(char *) 0);
  1871. X       /* XXX: warning? */
  1872. X       exit(1);
  1873. X      }
  1874. X     /* XXX: other special chars? */
  1875. X     switch(pos)
  1876. X      {
  1877. X       case 0:
  1878. X     r1 = ch;
  1879. X     ++pos;
  1880. X     if (flagecho)
  1881. X       write(1,&ch,1);
  1882. X     break;
  1883. X       case 1:
  1884. X     r2 = ch;
  1885. X     ++pos;
  1886. X     if (flagecho)
  1887. X       write(1,&ch,1);
  1888. X     break;
  1889. X       case 2:
  1890. X     ch = 7;
  1891. X     write(1,&ch,1);
  1892. X     break;
  1893. X      }
  1894. X    }
  1895. X  }
  1896. X newargv = (char **) malloc((argc + 4) * sizeof(char *));
  1897. X if (!newargv)
  1898. X   exit(1); /*XXXX*/
  1899. X
  1900. X for (i = 0;i <= argc;++i)
  1901. X   newargv[i + 2] = argv[i + 1];
  1902. X newargv[0] = "pty";
  1903. X newargv[1] = "-ds";
  1904. X execvp("pty",newargv,envp);
  1905. X /* XXX: warning? */
  1906. X exit(1);
  1907. X}
  1908. END_OF_FILE
  1909. if test 3294 -ne `wc -c <'sessmenu.c'`; then
  1910.     echo shar: \"'sessmenu.c'\" unpacked with wrong size!
  1911. fi
  1912. # end of 'sessmenu.c'
  1913. fi
  1914. if test -f 'sessname.c' -a "${1}" != "-c" ; then 
  1915.   echo shar: Will not clobber existing file \"'sessname.c'\"
  1916. else
  1917. echo shar: Extracting \"'sessname.c'\" \(2578 characters\)
  1918. sed "s/^X//" >'sessname.c' <<'END_OF_FILE'
  1919. X#include <stdio.h>
  1920. X#include "ptycomm.h"
  1921. X#include "config/ptydir.h"
  1922. X#include "config/ptylongname.h"
  1923. X#include "getopt.h"
  1924. X#include "env.h"
  1925. X
  1926. main(argc,argv)
  1927. int argc;
  1928. char *argv[];
  1929. X{
  1930. X int opt;
  1931. X int uid;
  1932. X char *ext;
  1933. X int fdcomm;
  1934. X char resp6[6];
  1935. X char longname[PTYLONGNAMELEN];
  1936. X
  1937. X uid = getuid();
  1938. X ext = env_get("PTY");
  1939. X while ((opt = getopt(argc,argv,"s:")) != opteof)
  1940. X   switch(opt)
  1941. X    {
  1942. X     case 's':
  1943. X       ext = optarg;
  1944. X       break;
  1945. X     case '?':
  1946. X     default:
  1947. X       exit(1);
  1948. X    }
  1949. X argc -= optind;
  1950. X argv += optind;
  1951. X
  1952. X if (*argv)
  1953. X  {
  1954. X   strncpy(longname,*argv,sizeof(longname));
  1955. X   longname[sizeof(longname) - 1] = 0;
  1956. X  }
  1957. X
  1958. X if (!ext)
  1959. X  {
  1960. X   fprintf(stderr,"%s: fatal: no -s specified, and PTY not set; are we under a session?\n",optprogname);
  1961. X   exit(2);
  1962. X  }
  1963. X
  1964. X if (chdir(PTYDIR) == -1)
  1965. X  {
  1966. X   fprintf(stderr,"%s: fatal: cannot change to session directory %s\n",optprogname,PTYDIR);
  1967. X   exit(2);
  1968. X  }
  1969. X
  1970. X fdcomm = comm_write(ext,uid);
  1971. X if (fdcomm == -1)
  1972. X  {
  1973. X   fprintf(stderr,"%s: fatal: cannot find session %s; if it exists, do you own it?\n",optprogname,ext);
  1974. X   exit(2);
  1975. X  }
  1976. X if (!*argv)
  1977. X  {
  1978. X   if (write(fdcomm,"l",1) < 1)
  1979. X    {
  1980. X     close(fdcomm);
  1981. X     fprintf(stderr,"%s: weird: session %s refuses to listen\n",optprogname,ext);
  1982. X     exit(2);
  1983. X    }
  1984. X   if (read(fdcomm,resp6,6) < 6)
  1985. X    {
  1986. X     close(fdcomm);
  1987. X     fprintf(stderr,"%s: weird: session %s refuses to respond\n",optprogname,ext);
  1988. X     exit(2);
  1989. X    }
  1990. X   if (!respeq(resp6,"longnm"))
  1991. X    {
  1992. X     close(fdcomm);
  1993. X     fprintf(stderr,"%s: weird: session %s is being quiet\n",optprogname,ext);
  1994. X     exit(2);
  1995. X    }
  1996. X   if (read(fdcomm,longname,sizeof(longname)) < sizeof(longname))
  1997. X    {
  1998. X     close(fdcomm);
  1999. X     fprintf(stderr,"%s: weird: session %s is being evasive\n",optprogname,ext);
  2000. X     exit(2);
  2001. X    }
  2002. X   close(fdcomm);
  2003. X   printf("session %c%c%s%s\n",ext[0],ext[1],longname[0] ? ": " : "",longname);
  2004. X  }
  2005. X else
  2006. X  {
  2007. X   if (write(fdcomm,"L",1) < 1)
  2008. X    {
  2009. X     close(fdcomm);
  2010. X     fprintf(stderr,"%s: weird: session %s refuses to listen\n",optprogname,ext);
  2011. X     exit(2);
  2012. X    }
  2013. X   if (write(fdcomm,longname,sizeof(longname)) < sizeof(longname))
  2014. X    {
  2015. X     close(fdcomm);
  2016. X     fprintf(stderr,"%s: fatal: session %s is deaf\n",optprogname,ext);
  2017. X     exit(2);
  2018. X    }
  2019. X   if (read(fdcomm,resp6,6) < 6)
  2020. X    {
  2021. X     close(fdcomm);
  2022. X     fprintf(stderr,"%s: weird: session %s refuses to respond\n",optprogname,ext);
  2023. X     exit(2);
  2024. X    }
  2025. X   if (!respeq(resp6,"thanks"))
  2026. X    {
  2027. X     close(fdcomm);
  2028. X     fprintf(stderr,"%s: fatal: session %s refuses to change\n",optprogname,ext);
  2029. X     exit(2);
  2030. X    }
  2031. X   close(fdcomm);
  2032. X  }
  2033. X
  2034. X exit(0);
  2035. X}
  2036. END_OF_FILE
  2037. if test 2578 -ne `wc -c <'sessname.c'`; then
  2038.     echo shar: \"'sessname.c'\" unpacked with wrong size!
  2039. fi
  2040. # end of 'sessname.c'
  2041. fi
  2042. if test -f 'sigdfl.c' -a "${1}" != "-c" ; then 
  2043.   echo shar: Will not clobber existing file \"'sigdfl.c'\"
  2044. else
  2045. echo shar: Extracting \"'sigdfl.c'\" \(3017 characters\)
  2046. sed "s/^X//" >'sigdfl.c' <<'END_OF_FILE'
  2047. X/* sigdfl.c, sigdfl.h: default signal library
  2048. Daniel J. Bernstein, brnstnd@nyu.edu.
  2049. No dependencies.
  2050. Requires BSD signal syscalls.
  2051. X1/27/92: Added ABRT->IOT ifndef.
  2052. X1/27/92: Switched from setting sv_flags to manually zeroing sigvecs.
  2053. X7/18/91: Baseline. sigdfl 1.0, public domain.
  2054. No known patent problems.
  2055. X
  2056. Documentation in sigdfl.3.
  2057. X
  2058. If you port this to System V, you don't have to worry about stop
  2059. signals; you can just have sigdfl_tstp() and friends return -1 with
  2060. XENOTTY. You are, however, faced with an incomplete, nearly prehistoric
  2061. signal interface. Have fun.
  2062. X*/
  2063. X
  2064. X#include <signal.h>
  2065. X#include "sigdfl.h"
  2066. X
  2067. static int cont = 0;
  2068. X
  2069. static sigcont() /* XXX: should declare with right signal type */
  2070. X{
  2071. X cont = 1;
  2072. X}
  2073. X
  2074. int sigdfl(sig)
  2075. int sig;
  2076. X{
  2077. X int oldmask;
  2078. X struct sigvec oldvec;
  2079. X struct sigvec vec;
  2080. X struct sigvec contvec;
  2081. X char *x;
  2082. X
  2083. X if (sig == SIGCONT)
  2084. X   return 0; /* strategy below simply cannot work for CONT */
  2085. X if ((sig == SIGURG) || (sig == SIGCHLD) || (sig == SIGIO)
  2086. X#ifdef SIGWINCH
  2087. X   || (sig == SIGWINCH)
  2088. X#endif
  2089. X    )
  2090. X   return 0; /* the above signals are ignored */
  2091. X /* XXX: If we're still going now, and sig can be delivered without */
  2092. X /* killing the process and without stopping the process so that it'll */
  2093. X /* receive CONT later, then we will enter an infinite loop. [sigh] */
  2094. X /* XXX: put maximum time wastage on this? */
  2095. X oldmask = sigblock(0);
  2096. X sigblock(~0);
  2097. X /* now we won't receive any signals */
  2098. X x = (char *) &vec; while (x < sizeof(vec) + (char *) &vec) *x++ = 0;
  2099. X vec.sv_handler = SIG_DFL;
  2100. X vec.sv_mask = ~0;
  2101. X if (sigvec(sig,&vec,&oldvec) == -1)
  2102. X   if ((sig != SIGSTOP) && (sig != SIGKILL))
  2103. X     return -1;
  2104. X x = (char *) &vec; while (x < sizeof(vec) + (char *) &vec) *x++ = 0;
  2105. X vec.sv_handler = sigcont;
  2106. X vec.sv_mask = ~0;
  2107. X if (sigvec(SIGCONT,&vec,&contvec) == -1)
  2108. X   return -1;
  2109. X cont = 0;
  2110. X if (kill(getpid(),sig) == -1)
  2111. X   return -1;
  2112. X /* now a sig should be queued, and we have control over sig and CONT */
  2113. X /* exception: SIGSTOP and SIGKILL can't be blocked, so those signals
  2114. X    might already have been delivered. in the SIGSTOP case, if we've
  2115. X    reached this point, sigcont() might already have been run. that's
  2116. X    why cont must be set to 0 before the kill(). */
  2117. X /* after this next bit we may receive sig and/or CONT */
  2118. X sigsetmask(~(sigmask(sig) | sigmask(SIGCONT)));
  2119. X /* in the near future, sig will in fact be received */
  2120. X while (!cont) /* dead loop until we receive CONT */
  2121. X   ; /* XXX: there should be a syscall so we don't have to loop here */
  2122. X sigblock(~0);
  2123. X /* now we won't receive any signals */
  2124. X (void) sigvec(sig,&oldvec,&vec); /* we don't care if it fails */
  2125. X (void) sigvec(SIGCONT,&contvec,&vec);
  2126. X /* now signal handlers are back to normal */
  2127. X (void) sigsetmask(oldmask);
  2128. X return 0;
  2129. X}
  2130. X
  2131. int sigdfl_tstp()
  2132. X{
  2133. X return sigdfl(SIGTSTP);
  2134. X}
  2135. X
  2136. int sigdfl_stop()
  2137. X{
  2138. X return sigdfl(SIGSTOP);
  2139. X}
  2140. X
  2141. int sigdfl_ttin()
  2142. X{
  2143. X return sigdfl(SIGTTIN);
  2144. X}
  2145. X
  2146. int sigdfl_ttou()
  2147. X{
  2148. X return sigdfl(SIGTTOU);
  2149. X}
  2150. X
  2151. int sigdfl_abrt()
  2152. X{
  2153. X#ifndef SIGABRT
  2154. X#define SIGABRT SIGIOT
  2155. X#endif
  2156. X return sigdfl(SIGABRT);
  2157. X}
  2158. END_OF_FILE
  2159. if test 3017 -ne `wc -c <'sigdfl.c'`; then
  2160.     echo shar: \"'sigdfl.c'\" unpacked with wrong size!
  2161. fi
  2162. # end of 'sigdfl.c'
  2163. fi
  2164. if test -f 'who.c' -a "${1}" != "-c" ; then 
  2165.   echo shar: Will not clobber existing file \"'who.c'\"
  2166. else
  2167. echo shar: Extracting \"'who.c'\" \(2317 characters\)
  2168. sed "s/^X//" >'who.c' <<'END_OF_FILE'
  2169. X/* who.c: clone of who program
  2170. Daniel J. Bernstein, brnstnd@nyu.edu.
  2171. Depends on getopt.h, fmt.h.
  2172. Requires BSD-style utmp and gethostname.
  2173. X7/22/91: Baseline. who 2.0, public domain.
  2174. No known patent problems.
  2175. X
  2176. Documentation in who.1.
  2177. X
  2178. This is based on the who.c that came with pty 3.0 but is much cleaner.
  2179. X*/
  2180. X
  2181. X#include <stdio.h>
  2182. X#include <sys/types.h>
  2183. X#include <utmp.h>
  2184. X#include <time.h>
  2185. extern char *asctime();
  2186. extern char *ttyname();
  2187. X#include "config/utmpfile.h"
  2188. X#include "getopt.h"
  2189. X#include "fmt.h"
  2190. X
  2191. main(argc,argv)
  2192. int argc;
  2193. char *argv[];
  2194. X{
  2195. X int opt;
  2196. X int flagloggedin;
  2197. X int flagwhoami;
  2198. X char *ttyn;
  2199. X static struct utmp ut;
  2200. X static char hostname[120];
  2201. X char *fn;
  2202. X FILE *fi;
  2203. X static char output[500];
  2204. X char *t;
  2205. X unsigned int len;
  2206. X
  2207. X flagloggedin = 2;
  2208. X flagwhoami = 0;
  2209. X while ((opt = getopt(argc,argv,"lL")) != opteof)
  2210. X   switch(opt)
  2211. X    {
  2212. X     case 'L':
  2213. X       flagloggedin = 1;
  2214. X       break;
  2215. X     case 'l':
  2216. X       flagloggedin = 0;
  2217. X       break;
  2218. X     case '?':
  2219. X     default:
  2220. X       exit(1);
  2221. X    }
  2222. X argc -= optind;
  2223. X argv += optind;
  2224. X
  2225. X if (argc > 1)
  2226. X  {
  2227. X   flagwhoami = 1;
  2228. X   if (!isatty(0))
  2229. X    {
  2230. X     fprintf(stderr,"who: fatal: stdin not a tty\n");
  2231. X     exit(1);
  2232. X    }
  2233. X   ttyn = ttyname(0) + 5; /* XXX: /dev/ */
  2234. X   gethostname(hostname,sizeof(hostname));
  2235. X  }
  2236. X
  2237. X if (flagloggedin == 2)
  2238. X   flagloggedin = !argc;
  2239. X fn = ((argc == 1) ? argv[0] : UTMP_FILE);
  2240. X
  2241. X if (!(fi = fopen(fn,"r")))
  2242. X  {
  2243. X   t = output;
  2244. X   t += fmt_strncpy(t,"who: cannot open ",0);
  2245. X   t += fmt_strncpy(t,fn,(output + sizeof(output)) - t - 3);
  2246. X   *t = 0;
  2247. X   perror(output);
  2248. X   exit(1);
  2249. X  }
  2250. X
  2251. X while (fread((char *) &ut,sizeof(ut),1,fi))
  2252. X  {
  2253. X   if (ut.ut_name[0] || !flagloggedin)
  2254. X     if (!flagwhoami || !strncmp(ut.ut_line,ttyn,8))
  2255. X      {
  2256. X       t = output;
  2257. X       if (flagwhoami)
  2258. X    {
  2259. X     t += fmt_strncpy(t,hostname,0);
  2260. X     *t++ = '!';
  2261. X    }
  2262. X       len = fmt_strncpy(t,"        ",0);
  2263. X       t[fmt_strncpy(t,ut.ut_name,len)] = ' '; t += len; *t++ = ' ';
  2264. X       len = fmt_strncpy(t,"        ",0);
  2265. X       t[fmt_strncpy(t,ut.ut_line,len)] = ' '; t += len;
  2266. X       len = fmt_strncpy(t,"            ",0);
  2267. X       t[fmt_strncpy(t,asctime(localtime(&ut.ut_time)) + 4,len)] = ' ';
  2268. X       t += len;
  2269. X       if (ut.ut_host[0])
  2270. X    {
  2271. X     *t++ = '\t';
  2272. X     *t++ = '(';
  2273. X     t += fmt_strncpy(t,ut.ut_host,16);
  2274. X     *t++ = ')';
  2275. X    }
  2276. X       *t = 0;
  2277. X       puts(output);
  2278. X      }
  2279. X  }
  2280. X exit(0);
  2281. X}
  2282. END_OF_FILE
  2283. if test 2317 -ne `wc -c <'who.c'`; then
  2284.     echo shar: \"'who.c'\" unpacked with wrong size!
  2285. fi
  2286. # end of 'who.c'
  2287. fi
  2288. if test -f 'write.c' -a "${1}" != "-c" ; then 
  2289.   echo shar: Will not clobber existing file \"'write.c'\"
  2290. else
  2291. echo shar: Extracting \"'write.c'\" \(2757 characters\)
  2292. sed "s/^X//" >'write.c' <<'END_OF_FILE'
  2293. X/* Public domain. */
  2294. X
  2295. X#include <sys/types.h>
  2296. X#include <sys/stat.h>
  2297. X#include <sys/file.h>
  2298. X#ifdef BSD
  2299. X#include <limits.h>
  2300. X#endif
  2301. X#include <stdio.h>
  2302. X#include <strings.h>
  2303. X#include <utmp.h>
  2304. X#include <pwd.h>
  2305. X#include <time.h>
  2306. X#include "config/utmpfile.h"
  2307. X#include "fmt.h"
  2308. extern unsigned short getuid();
  2309. extern char *ttyname();
  2310. extern long time();
  2311. X
  2312. main(argc,argv)
  2313. int argc;
  2314. char *argv[];
  2315. X{ 
  2316. X register FILE *fi;
  2317. X struct utmp ut;
  2318. X char line[9];
  2319. X int lines = 0;
  2320. X char fntty[30];
  2321. X int fd;
  2322. X struct stat st;
  2323. X char buf[500];
  2324. X char outbuf[3000];
  2325. X int offset;
  2326. X char *username;
  2327. X struct passwd *pw;
  2328. X char hostname[64];
  2329. X char *ttyn;
  2330. X long t;
  2331. X struct tm *tm;
  2332. X char *s;
  2333. X
  2334. X if (argc < 2)
  2335. X  {
  2336. X   fputs("Usage: write user [ttyname]\n",stderr);
  2337. X   exit(1);
  2338. X  }
  2339. X
  2340. X if (!(pw = getpwuid((int) getuid())))
  2341. X  {
  2342. X   fputs("write: who are you?\n",stderr);
  2343. X   exit(1);
  2344. X  }
  2345. X username = pw->pw_name;
  2346. X
  2347. X gethostname(hostname,sizeof(hostname));
  2348. X hostname[sizeof(hostname) - 1] = 0;
  2349. X
  2350. X if (!(ttyn = ttyname(2)))
  2351. X  {
  2352. X   fputs("write: Can't find your tty\n",stderr);
  2353. X   exit(1);
  2354. X  }
  2355. X if ((fstat(2,&st) == -1) || !(st.st_mode & 0020))
  2356. X   fputs("write: warning: your messages are off, recipient will not be able to respond\n",stderr);
  2357. X
  2358. X t = time((long *) 0);
  2359. X tm = localtime(&t);
  2360. X
  2361. X if (fi = fopen(UTMP_FILE,"r"))
  2362. X   while (fread((char *) &ut,sizeof(ut),1,fi))
  2363. X     if (!strncmp(ut.ut_name,argv[1],8))
  2364. X       if ((argc == 2) || (!strncmp(ut.ut_line,argv[2],8)))
  2365. X     if (!lines)
  2366. X      {
  2367. X       fmt_strncpy(line,ut.ut_line,8);
  2368. X       line[8] = '\0';
  2369. X       lines = 1;
  2370. X      }
  2371. X     else
  2372. X       lines++;
  2373. X if (!lines)
  2374. X  {
  2375. X   if (argc == 2)
  2376. X     (void) fprintf(stderr,"write: %s not logged in\n",argv[1]);
  2377. X   else
  2378. X     (void) fprintf(stderr,"write: %s not logged in on tty %s\n",
  2379. X            argv[1],argv[2]);
  2380. X   (void) exit(1);
  2381. X  }
  2382. X if (lines > 1)
  2383. X   (void) fprintf(stderr,
  2384. X   "write: %s logged in more than once ... writing to %s\n",
  2385. X   argv[1],line);
  2386. X
  2387. X (void) sprintf(fntty,"/dev/%s",line);
  2388. X if ((fd = open(fntty,O_WRONLY)) == -1)
  2389. X  {
  2390. X   fputs("write: Permission denied\n",stderr);
  2391. X   exit(1);
  2392. X  }
  2393. X
  2394. X (void) sprintf(buf,"\nMessage from %s@%s on %s at %d:%02d ...%c\n",
  2395. X        username,hostname,ttyn + 5,tm->tm_hour,tm->tm_min,7);
  2396. X (void) write(fd,buf,strlen(buf));
  2397. X
  2398. X (void) sprintf(buf,"%s: ",username);
  2399. X offset = strlen(buf);
  2400. X
  2401. X while (fgets(buf + offset,sizeof(buf) - offset,stdin))
  2402. X  {
  2403. X   if ((fstat(fd,&st) == -1) || !(st.st_mode & 0020))
  2404. X    {
  2405. X     fprintf(stderr,"write: Permission denied\n");
  2406. X     exit(1);
  2407. X    }
  2408. X   s = outbuf + fmt_nvis(outbuf,buf,strlen(buf));
  2409. X   write(fd,outbuf,s - outbuf); /*XXX*/
  2410. X   sleep(1);
  2411. X  }
  2412. X
  2413. X t = time((long *) 0);
  2414. X tm = localtime(&t);
  2415. X (void) sprintf(buf,"End of message from %s@%s on %s at %d:%02d\n",
  2416. X        username,hostname,ttyn + 5,tm->tm_hour,tm->tm_min);
  2417. X (void) write(fd,buf,strlen(buf));
  2418. X
  2419. X exit(0);
  2420. X}
  2421. END_OF_FILE
  2422. if test 2757 -ne `wc -c <'write.c'`; then
  2423.     echo shar: \"'write.c'\" unpacked with wrong size!
  2424. fi
  2425. # end of 'write.c'
  2426. fi
  2427. echo shar: End of archive 3 \(of 9\).
  2428. cp /dev/null ark3isdone
  2429. MISSING=""
  2430. for I in 1 2 3 4 5 6 7 8 9 ; do
  2431.     if test ! -f ark${I}isdone ; then
  2432.     MISSING="${MISSING} ${I}"
  2433.     fi
  2434. done
  2435. if test "${MISSING}" = "" ; then
  2436.     echo You have unpacked all 9 archives.
  2437.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2438. else
  2439.     echo You still need to unpack the following archives:
  2440.     echo "        " ${MISSING}
  2441. fi
  2442. ##  End of shell archive.
  2443. exit 0
  2444.